﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Windows.Forms;

namespace Rsdn.Shortcuts
{
    /// <summary>
    /// Summary description for DesignShortcut.
    /// </summary>
    public class DesignShortcuts : Form, IDialogContainer
    {
        #region  Class Variables
        private readonly ShortcutManager _manager;
        private Button _applyButton;
        private Button _cancelButton;
        private Panel _containerPanel;
        private ImageList _imageList;
        private ListBoxShortcuts _listBox;
        private Label _longNameLabel;
        private Button _okButton;
        private Panel _panel1;
        private Panel _panel2;
        private Panel _panel3;
        private Panel _panel4;
        private Panel _panel5;
        private Button _refreshButton;
        private CustomShortcut _shortcut;
        private Label _shortNameLabel;
        private Splitter _splitter1;
        private Splitter _splitter2;
        private ToolBar _toolbar;
        private ToolBarButton _toolBarButton1;
        private ToolBarButton _toolBarButton2;
        private TreeView _treeView;
        private IContainer components;
        #endregion

        #region Constructor
        public DesignShortcuts(ShortcutManager manager)
        {
            _manager = manager;

            InitializeComponent();
            CustomInitializeComponent();
        }
        #endregion

        #region Designer generated code
        protected override void Dispose(bool disposing)
        {
            if (disposing)
                if (components != null)
                    components.Dispose();

            base.Dispose(disposing);
        }
        #endregion

        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DesignShortcuts));
            this._treeView = new System.Windows.Forms.TreeView();
            this._imageList = new System.Windows.Forms.ImageList(this.components);
            this._okButton = new System.Windows.Forms.Button();
            this._cancelButton = new System.Windows.Forms.Button();
            this._refreshButton = new System.Windows.Forms.Button();
            this._applyButton = new System.Windows.Forms.Button();
            this._panel2 = new System.Windows.Forms.Panel();
            this._panel3 = new System.Windows.Forms.Panel();
            this._panel1 = new System.Windows.Forms.Panel();
            this._listBox = new Rsdn.Shortcuts.ListBoxShortcuts();
            this._splitter2 = new System.Windows.Forms.Splitter();
            this._panel4 = new System.Windows.Forms.Panel();
            this._panel5 = new System.Windows.Forms.Panel();
            this._longNameLabel = new System.Windows.Forms.Label();
            this._shortNameLabel = new System.Windows.Forms.Label();
            this._containerPanel = new System.Windows.Forms.Panel();
            this._splitter1 = new System.Windows.Forms.Splitter();
            this._toolbar = new System.Windows.Forms.ToolBar();
            this._toolBarButton1 = new System.Windows.Forms.ToolBarButton();
            this._toolBarButton2 = new System.Windows.Forms.ToolBarButton();
            this._panel2.SuspendLayout();
            this._panel3.SuspendLayout();
            this._panel1.SuspendLayout();
            this._panel4.SuspendLayout();
            this._panel5.SuspendLayout();
            this._containerPanel.SuspendLayout();
            this.SuspendLayout();
            // 
            // _treeView
            // 
            this._treeView.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(255)))), ((int)(((byte)(224)))));
            this._treeView.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this._treeView.Cursor = System.Windows.Forms.Cursors.Default;
            this._treeView.Dock = System.Windows.Forms.DockStyle.Fill;
            this._treeView.ImageIndex = 0;
            this._treeView.ImageList = this._imageList;
            this._treeView.Location = new System.Drawing.Point(0, 0);
            this._treeView.Name = "_treeView";
            this._treeView.SelectedImageIndex = 0;
            this._treeView.Size = new System.Drawing.Size(205, 369);
            this._treeView.TabIndex = 0;
            this._treeView.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.treeView1_AfterSelect);
            this._treeView.BeforeSelect += new System.Windows.Forms.TreeViewCancelEventHandler(this.treeView1_BeforeSelect);
            // 
            // _imageList
            // 
            this._imageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("_imageList.ImageStream")));
            this._imageList.TransparentColor = System.Drawing.Color.Transparent;
            this._imageList.Images.SetKeyName(0, "");
            this._imageList.Images.SetKeyName(1, "");
            // 
            // _okButton
            // 
            this._okButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
            this._okButton.Location = new System.Drawing.Point(7, 10);
            this._okButton.Name = "_okButton";
            this._okButton.Size = new System.Drawing.Size(75, 23);
            this._okButton.TabIndex = 2;
            this._okButton.Text = "OK";
            this._okButton.Click += new System.EventHandler(this._okButton_Click);
            // 
            // _cancelButton
            // 
            this._cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
            this._cancelButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
            this._cancelButton.Location = new System.Drawing.Point(96, 10);
            this._cancelButton.Name = "_cancelButton";
            this._cancelButton.Size = new System.Drawing.Size(75, 23);
            this._cancelButton.TabIndex = 3;
            this._cancelButton.Text = "Отмена";
            this._cancelButton.Click += new System.EventHandler(this._cancelButton_Click);
            // 
            // _refreshButton
            // 
            this._refreshButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
            this._refreshButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
            this._refreshButton.Location = new System.Drawing.Point(402, 10);
            this._refreshButton.Name = "_refreshButton";
            this._refreshButton.Size = new System.Drawing.Size(96, 23);
            this._refreshButton.TabIndex = 5;
            this._refreshButton.Text = "По умолчанию";
            this._refreshButton.Click += new System.EventHandler(this._refreshButton_Click);
            // 
            // _applyButton
            // 
            this._applyButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
            this._applyButton.Location = new System.Drawing.Point(184, 10);
            this._applyButton.Name = "_applyButton";
            this._applyButton.Size = new System.Drawing.Size(75, 23);
            this._applyButton.TabIndex = 4;
            this._applyButton.Text = "Применить";
            this._applyButton.Click += new System.EventHandler(this._applyButton_Click);
            // 
            // _panel2
            // 
            this._panel2.Controls.Add(this._treeView);
            this._panel2.Dock = System.Windows.Forms.DockStyle.Left;
            this._panel2.Location = new System.Drawing.Point(0, 42);
            this._panel2.Name = "_panel2";
            this._panel2.Size = new System.Drawing.Size(205, 369);
            this._panel2.TabIndex = 9;
            // 
            // _panel3
            // 
            this._panel3.Controls.Add(this._okButton);
            this._panel3.Controls.Add(this._cancelButton);
            this._panel3.Controls.Add(this._applyButton);
            this._panel3.Controls.Add(this._refreshButton);
            this._panel3.Dock = System.Windows.Forms.DockStyle.Bottom;
            this._panel3.Location = new System.Drawing.Point(0, 411);
            this._panel3.Name = "_panel3";
            this._panel3.Size = new System.Drawing.Size(506, 44);
            this._panel3.TabIndex = 10;
            // 
            // _panel1
            // 
            this._panel1.Controls.Add(this._listBox);
            this._panel1.Controls.Add(this._splitter2);
            this._panel1.Controls.Add(this._panel4);
            this._panel1.Dock = System.Windows.Forms.DockStyle.Fill;
            this._panel1.Location = new System.Drawing.Point(209, 42);
            this._panel1.Name = "_panel1";
            this._panel1.Size = new System.Drawing.Size(297, 369);
            this._panel1.TabIndex = 12;
            // 
            // _listBox
            // 
            this._listBox.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(255)))));
            this._listBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this._listBox.Dock = System.Windows.Forms.DockStyle.Fill;
            this._listBox.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed;
            this._listBox.IntegralHeight = false;
            this._listBox.ItemHeight = 15;
            this._listBox.Location = new System.Drawing.Point(0, 0);
            this._listBox.Name = "_listBox";
            this._listBox.Size = new System.Drawing.Size(297, 282);
            this._listBox.TabIndex = 0;
            this._listBox.SelectedValueChanged += new System.EventHandler(this.listBox1_SelectedValueChanged);
            // 
            // _splitter2
            // 
            this._splitter2.Dock = System.Windows.Forms.DockStyle.Bottom;
            this._splitter2.Location = new System.Drawing.Point(0, 282);
            this._splitter2.Name = "_splitter2";
            this._splitter2.Size = new System.Drawing.Size(297, 2);
            this._splitter2.TabIndex = 2;
            this._splitter2.TabStop = false;
            // 
            // _panel4
            // 
            this._panel4.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this._panel4.Controls.Add(this._panel5);
            this._panel4.Dock = System.Windows.Forms.DockStyle.Bottom;
            this._panel4.Location = new System.Drawing.Point(0, 284);
            this._panel4.Name = "_panel4";
            this._panel4.Padding = new System.Windows.Forms.Padding(2);
            this._panel4.Size = new System.Drawing.Size(297, 85);
            this._panel4.TabIndex = 1;
            // 
            // _panel5
            // 
            this._panel5.Controls.Add(this._longNameLabel);
            this._panel5.Controls.Add(this._shortNameLabel);
            this._panel5.Dock = System.Windows.Forms.DockStyle.Fill;
            this._panel5.ForeColor = System.Drawing.SystemColors.ControlDarkDark;
            this._panel5.Location = new System.Drawing.Point(2, 2);
            this._panel5.Name = "_panel5";
            this._panel5.Size = new System.Drawing.Size(291, 79);
            this._panel5.TabIndex = 0;
            // 
            // _longNameLabel
            // 
            this._longNameLabel.Dock = System.Windows.Forms.DockStyle.Fill;
            this._longNameLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
            this._longNameLabel.Location = new System.Drawing.Point(0, 15);
            this._longNameLabel.Name = "_longNameLabel";
            this._longNameLabel.Size = new System.Drawing.Size(291, 64);
            this._longNameLabel.TabIndex = 1;
            this._longNameLabel.Text = "label1";
            // 
            // _shortNameLabel
            // 
            this._shortNameLabel.Dock = System.Windows.Forms.DockStyle.Top;
            this._shortNameLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
            this._shortNameLabel.Location = new System.Drawing.Point(0, 0);
            this._shortNameLabel.Name = "_shortNameLabel";
            this._shortNameLabel.Size = new System.Drawing.Size(291, 15);
            this._shortNameLabel.TabIndex = 0;
            this._shortNameLabel.Text = "label1";
            // 
            // _containerPanel
            // 
            this._containerPanel.Controls.Add(this._panel1);
            this._containerPanel.Controls.Add(this._splitter1);
            this._containerPanel.Controls.Add(this._panel2);
            this._containerPanel.Controls.Add(this._toolbar);
            this._containerPanel.Dock = System.Windows.Forms.DockStyle.Fill;
            this._containerPanel.Location = new System.Drawing.Point(0, 0);
            this._containerPanel.Name = "_containerPanel";
            this._containerPanel.Size = new System.Drawing.Size(506, 411);
            this._containerPanel.TabIndex = 13;
            // 
            // _splitter1
            // 
            this._splitter1.Location = new System.Drawing.Point(205, 42);
            this._splitter1.Name = "_splitter1";
            this._splitter1.Size = new System.Drawing.Size(4, 369);
            this._splitter1.TabIndex = 10;
            this._splitter1.TabStop = false;
            // 
            // _toolbar
            // 
            this._toolbar.Buttons.AddRange(new System.Windows.Forms.ToolBarButton[] {
            this._toolBarButton1,
            this._toolBarButton2});
            this._toolbar.DropDownArrows = true;
            this._toolbar.Location = new System.Drawing.Point(0, 0);
            this._toolbar.Name = "_toolbar";
            this._toolbar.ShowToolTips = true;
            this._toolbar.Size = new System.Drawing.Size(506, 42);
            this._toolbar.TabIndex = 13;
            this._toolbar.ButtonClick += new System.Windows.Forms.ToolBarButtonClickEventHandler(this._toolbar_ButtonClick);
            // 
            // _toolBarButton1
            // 
            this._toolBarButton1.Name = "_toolBarButton1";
            this._toolBarButton1.Tag = "SaveAsPreset";
            this._toolBarButton1.Text = "Сохранить как пресет";
            this._toolBarButton1.ToolTipText = "Сохранить как пресет";
            // 
            // _toolBarButton2
            // 
            this._toolBarButton2.Name = "_toolBarButton2";
            this._toolBarButton2.Tag = "LoadPreset";
            this._toolBarButton2.Text = "Загрузить пресет";
            this._toolBarButton2.ToolTipText = "Загрузить пресет";
            // 
            // DesignShortcuts
            // 
            this.AcceptButton = this._okButton;
            this.CancelButton = this._cancelButton;
            this.ClientSize = new System.Drawing.Size(506, 455);
            this.Controls.Add(this._containerPanel);
            this.Controls.Add(this._panel3);
            this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
            this.MaximizeBox = false;
            this.Name = "DesignShortcuts";
            this.Text = "Настройка горячих клавиш";
            this._panel2.ResumeLayout(false);
            this._panel3.ResumeLayout(false);
            this._panel1.ResumeLayout(false);
            this._panel4.ResumeLayout(false);
            this._panel5.ResumeLayout(false);
            this._containerPanel.ResumeLayout(false);
            this._containerPanel.PerformLayout();
            this.ResumeLayout(false);

        }
        #endregion

        #region Implementation
        public Control GetDialog()
        {
            return _containerPanel;
        }

        public void AcceptChanges()
        {
            ReFillHashTable();
            //ShortcutManager.Instance.Tree = tree;
            Close();
            //Hide();
        }

        public void RejectChanges()
        {
            Close();
        }

        private void CustomInitializeComponent()
        {
            LoadShortcuts();
        }

        private void LoadShortcuts()
        {
            try
            {
                _treeView.BeginUpdate();
                _treeView.Nodes.Clear();
                BuildTree(_treeView.Nodes, _manager.Nodes);
            }
            finally
            {
                _treeView.EndUpdate();
            }

            _shortcut = null;

            if (_treeView.Nodes.Count > 0)
            {
                _treeView.SelectedNode = _treeView.Nodes[0];
                _treeView.ExpandAll();
            }
        }

        private static void BuildTree(TreeNodeCollection treeNodes, ShortcutCollection shortcutNodes)
        {
            foreach (CustomShortcut shortcut in shortcutNodes)
            {
                TreeNode node = new TreeNode(shortcut.Name, 0, 1);
                node.Tag = shortcut;

                treeNodes.Add(node);

                BuildTree(node.Nodes, shortcut.Nodes);
            }
        }

        private void ReFillHashTable()
        {
            if (_listBox.Items.Count != 0 && _shortcut != null)
            {
                _shortcut.HashTable.Clear();

                foreach (TextShortcut ts in _listBox.Items)
                {
                    if (ts.Shortcut != Shortcut.None)
                    {
                        _shortcut.HashTable[ts.Shortcut] = ts.MethodName;
                    }
                }
            }
        }

        /// <summary>
        /// Fills the list box rights
        /// Scan defined type and search methods with MethodShortcut attributes
        /// </summary>
        /// <param name="refresh">if set to <c>true</c> [refresh].</param>
        private void FillListBox(bool refresh)
        {
            _listBox.Items.Clear();

            Dictionary<string, Shortcut> shortcuts = new Dictionary<string, Shortcut>();

            foreach (KeyValuePair<Shortcut, string> sc in _shortcut.HashTable)
            {
                shortcuts[sc.Value] = sc.Key;
            }

            BindingFlags bindingAttr =
                BindingFlags.DeclaredOnly
                | BindingFlags.Instance
                | BindingFlags.Static
                | BindingFlags.Public
                | BindingFlags.NonPublic;


            MethodInfo[] methodInfos = _shortcut.OwnerType.GetMethods(bindingAttr);
            foreach (MethodInfo methodInfo in methodInfos)
            {
                MethodShortcutAttribute attr = (MethodShortcutAttribute)Attribute.GetCustomAttribute(methodInfo, typeof(MethodShortcutAttribute));

                if (attr != null)
                {
                    if (refresh)
                    {
                        TextShortcut shortcut = new TextShortcut(methodInfo.Name, attr.ShortName, attr.LongName, attr.Shortcut);
                        _listBox.Items.Add(shortcut);
                    }
                    else
                    {
                        Shortcut shortcut;
                        if (!shortcuts.TryGetValue(methodInfo.Name, out shortcut))
                        {
                            shortcut = Shortcut.None;
                        }

                        TextShortcut textShortcut = new TextShortcut(methodInfo.Name, attr.ShortName, attr.LongName, shortcut);
                        _listBox.Items.Add(textShortcut);
                    }
                }
            }
        }

        private void ProcessToolbarClick(string action)
        {
            switch (action)
            {
                case "SaveAsPreset":
                    SaveAsPreset();
                    break;
                case "LoadPreset":
                    LoadPreset();
                    break;
            }
        }

        private void SaveAsPreset()
        {
            ReFillHashTable();

            using (var spf = new SavePresetForm())
            {
                if (spf.ShowDialog() == DialogResult.OK)
                {
                    _manager.SaveCurrentAsPreset(spf.PresetName);
                }
            }
        }

        private void LoadPreset()
        {
            using (var spf = new SelectPresetForm(_manager))
            {
                spf.LoadPresets(_manager.Presets);
                if (spf.ShowDialog() == DialogResult.OK)
                {
                    _manager.LoadPreset(spf.PresetName);
                    LoadShortcuts();
                    //FillListBox(true);
                    FillListBox(false);
                }
            }
        }
        #endregion

        #region Events
        private void treeView1_BeforeSelect(object sender, TreeViewCancelEventArgs e)
        {
            _shortNameLabel.Text = string.Empty;
            _longNameLabel.Text = string.Empty;

            ReFillHashTable();
        }

        private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
        {
            _shortcut = (CustomShortcut)e.Node.Tag;
            FillListBox(false);
        }

        private void _okButton_Click(object sender, EventArgs e)
        {
            AcceptChanges();
        }

        private void _cancelButton_Click(object sender, EventArgs e)
        {
            Close();
            //Hide();
        }

        private void _refreshButton_Click(object sender, EventArgs e)
        {
            FillListBox(true);
        }

        private void listBox1_SelectedValueChanged(object sender, EventArgs e)
        {
            if (_listBox.SelectedItem != null)
            {
                var ts = (TextShortcut)_listBox.SelectedItem;

                _shortNameLabel.Text = ts.ShortName;
                _longNameLabel.Text = ts.LongName;
            }
        }

        private void _applyButton_Click(object sender, EventArgs e)
        {
            ReFillHashTable();
            //ShortcutManager.Instance.Tree = tree;
        }

        private void _toolbar_ButtonClick(object sender, ToolBarButtonClickEventArgs e)
        {
            ProcessToolbarClick(e.Button.Tag.ToString());
        }
        #endregion
    }
}